<template>
  <el-form
    label-width="100px"
    :rules="spuRules"
    :model="spuInfo"
    ref="spuFormRef"
  >
    <!-- SPU名称 -->
    <el-form-item label="SPU名称" prop="spuName">
      <el-input placeholder="SPU名称" v-model="spuInfo.spuName"></el-input>
    </el-form-item>
    <!-- SPU品牌 -->
    <el-form-item label="SPU品牌" prop="tmId">
      <el-select placeholder="请选择品牌" v-model="spuInfo.tmId">
        <el-option
          v-for="tm in trademarkList"
          :key="tm.id"
          :label="tm.tmName"
          :value="tm.id"
        />
      </el-select>
    </el-form-item>
    <!-- SPU描述 -->
    <el-form-item label="SPU描述" prop="description">
      <el-input
        type="textarea"
        rows="3"
        v-model="spuInfo.description"
      ></el-input>
    </el-form-item>
    <!-- SPU图片 -->
    <el-form-item label="SPU图片" prop="spuImageList">
      <el-upload
        v-model:file-list="spuInfo.spuImageList"
        :action="`${BASE_URL}/admin/product/upload`"
        list-type="picture-card"
        :on-preview="handlePictureCardPreview"
        :on-remove="handleRemove"
        :on-success="handleAvatarSuccess"
        :before-upload="beforeAvatarUpload"
      >
        <el-icon><Plus /></el-icon>
      </el-upload>
    </el-form-item>
    <!-- 销售属性 -->
    <el-form-item label="销售属性" prop="spuSaleAttrList">
      <el-select
        v-model="spuInfo.spuSaleAttr"
        :placeholder="`还有${filterBaseSaleAttrList.length}个待选择`"
      >
        <el-option
          v-for="baseSale in filterBaseSaleAttrList"
          :key="baseSale.id"
          :label="baseSale.name"
          :value="baseSale.name"
        ></el-option>
      </el-select>
      <el-button
        type="primary"
        style="margin: 0 8px"
        @click="addSpuSaleAttr"
        :disabled="!spuInfo.spuSaleAttr"
        >添加销售属性</el-button
      >
      <!-- 销售属性数据 表格渲染 -->
      <el-table :data="spuInfo.spuSaleAttrList" border style="margin: 15px 0">
        <el-table-column
          type="index"
          label="序号"
          width="80px"
          align="center"
        ></el-table-column>
        <el-table-column
          label="属性名"
          prop="saleAttrName"
          width="100px"
        ></el-table-column>
        <el-table-column label="属性值列表">
          <template v-slot="{ row, $index }">
            <el-tag
              type="success"
              v-for="tag in row.spuSaleAttrValueList"
              :key="tag"
              class="mx-1"
              closable
              style="margin-right: 3px"
              :disable-transitions="false"
              @close="handleClose(row, tag)"
            >
              {{ tag.saleAttrValueName }}
            </el-tag>
            <el-input
              v-if="row.inputVisible"
              ref="InputRef"
              v-model="inputValue"
              class="ml-1 w-20"
              size="small"
              @keyup.enter="handleInputConfirm(row)"
              @blur="handleInputConfirm(row)"
            />
            <el-button
              v-else
              class="button-new-tag ml-1"
              size="small"
              @click="showInput(row)"
            >
              +New
            </el-button>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200px" align="center">
          <template v-slot="{ $index }">
            <el-popconfirm
              title="确定要删除此属性吗?"
              @confirm="deleteAttr($index)"
            >
              <template #reference
                ><el-button
                  title="删除SPU"
                  type="danger"
                  size="small"
                  :icon="Delete"
                ></el-button
              ></template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
    </el-form-item>
    <!-- 保存、取消按钮 -->
    <el-form-item>
      <el-button type="primary" @click="spuSubmitForm(spuFormRef)"
        >保存</el-button
      >
      <el-button @click="emits('changeScene', 1)">取消</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts">
export default {
  name: "SpuForm",
}
</script>

<script lang="ts" setup>
import { ref, onMounted, reactive, nextTick, computed } from "vue"
import { Plus, Delete } from "@element-plus/icons-vue"
import { ElMessage } from "element-plus"
import type {
  UploadProps,
  UploadFile,
  UploadFiles,
  ElInput,
  FormRules,
  FormInstance,
} from "element-plus"
import {
  reqGetAllTrademarkList,
  reqGetBaseSaleAttrList,
  reqSaveSpuInfo,
  reqGetSpuImageList,
  reqGetSpuSaleAttrList,
  reqUpdateSpuInfo,
} from "@/api/product/spu.ts"
import { useCategoryListStore } from "@/stores/categoryList"
const emits = defineEmits(["changeScene"])
const props = defineProps(["currentSpuInfo"])
const categoryStore = useCategoryListStore()
// 保存照片墙的变量
const dialogImageUrl = ref("")
const dialogVisible = ref(false)
// 动态读取环境变量中的值
const BASE_URL = import.meta.env.VITE_API_URL

// 属性值列表 tag 的变量
const inputValue = ref("")
const dynamicTags = ref(["Tag 1", "Tag 2", "Tag 3"])
const InputRef = ref<InstanceType<typeof ElInput>>()

// 定义两个变量 来存储品牌列表和基础销售属性
const trademarkList = ref([])
const baseSaleAttrList = ref([])

// 定义一个存储spu相关数据的变量
const spuInfo = reactive({
  spuName: "", // spu的名称
  tmId: "", // spu品牌
  description: "", // spu描述
  spuSaleAttr: "", // 收集选中的属性 颜色 版本  尺寸
  category3Id: "", // 三级id
  ...props.currentSpuInfo,
  //因为props中的 这两项为undefined 所有将 这两项 移到下边 就不会报错
  spuImageList: [], // 存储spu图片的数组
  spuSaleAttrList: [], // 基本销售属性
})

// form表单校验
const spuFormRef = ref<FormInstance>()
const spuRules = reactive<FormRules>({
  spuName: [
    { required: true, message: "请输入SPU名称", trigger: "blur" },
    { min: 1, max: 10, message: "长度在1--10之间", trigger: "blur" },
  ],
  tmId: [{ required: true, message: "请选择品牌名称", trigger: "change" }],
  description: [{ required: true, message: "请添加SPU描述", trigger: "blur" }],
  spuImageList: [
    {
      type: "array",
      required: true,
      message: "请至少上传一张图片",
      trigger: "change",
    },
  ],
  spuSaleAttrList: [
    {
      type: "array",
      required: true,
      message: "请添加销售属性",
      trigger: "change",
    },
  ],
})

// 1. 组件一挂载完毕，就要去发送请求 获取品牌列表和销售属性的值
onMounted(async () => {
  console.log("spuForm组件挂载了")
  console.log(props.currentSpuInfo)

  // 我们可以借助于一个Promise.all([])方法，一次性发送多个请求，当请求成功后，会将数据按书写顺序依次赋值  只要成功就会按书写顺序 无论哪个快慢
  // Promise.all([])如果有一个失败了，则整体都是失败的
  try {
    const id = spuInfo.id
    let promises = [reqGetAllTrademarkList(), reqGetBaseSaleAttrList()]
    if (id) {
      promises = promises.concat(
        reqGetSpuImageList(id),
        reqGetSpuSaleAttrList(id)
      )
    }
    const [
      resTrademarkList,
      resBaseSaleAttrList,
      resSpuImageList,
      resSpuSaleAttrList,
    ] = await Promise.all(promises)
    // 缓存接口返回的数据
    trademarkList.value = resTrademarkList
    baseSaleAttrList.value = resBaseSaleAttrList
    if (resSpuImageList && resSpuSaleAttrList) {
      spuInfo.spuImageList = resSpuImageList.map(item => {
        return {
          ...item,
          name: item.imgName,
          url: item.imgUrl,
        }
      })
      spuInfo.spuSaleAttrList = resSpuSaleAttrList
    }
  } catch (error) {
    ElMessage.error("获取品牌或属性失败...")
  }
})

// 照片墙相关的函数
// 2.图片删除时触发的函数
const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
  // console.log(uploadFile, uploadFiles)
  // uploadFile表示删除了的图片的信息
  // uploadFiles 表示剩余的图片信息
  // 将剩余的图片信息存到这个数组当中，在最终上传之前，再处理一下
  spuInfo.spuImageList = uploadFiles
}
// 3.图片预览时触发的函数
const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => {
  dialogImageUrl.value = uploadFile.url!
  dialogVisible.value = true
}
// 4.图片上传时触发的函数
const handleAvatarSuccess: UploadProps["onSuccess"] = (
  response: any,
  uploadFile: UploadFile,
  uploadFiles: UploadFiles
) => {
  // response是服务器响应回来的结果  里面的data属性就有图片在服务器端的地址
  // uploadFile 是经过改造的响应对象 不但包含图片在服务器响应回来的结果  还包含图片本身的信息
  // uploadFiles 相当于是上传的所有的图片的数组
  // console.log("up", response, uploadFile, uploadFiles)
  // 将照片墙中的图片先存放在一个数组中
  // spuInfo.spuImageList.push({
  //   imgName: uploadFile.name,
  //   imgUrl: response.data,
  // })
  spuInfo.spuImageList = uploadFiles

  // 清空图片校验规则
  spuFormRef.value!.clearValidate(["spuImageList"])
}
// 5. 图片上传之前校验时要执行的事件处理程序
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
  const imgTypes = ["image/jpeg", "image/jpg", "image/png"]
  // if (rawFile.type !== 'image/jpeg') {
  if (!imgTypes.includes(rawFile.type)) {
    ElMessage.error("上传的图片格式必须是JPG/JPEG/PNG格式,请重试")
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    // 1G=1024M 1M=1024K 1K=1024byte
    ElMessage.error("图片最大不能超过2M,请重试!")
    return false
  }
  return true
}

// 6. 添加基础销售属性
const addSpuSaleAttr = () => {
  const spuSaleAttrList = spuInfo.spuSaleAttrList
  if (
    spuSaleAttrList.length &&
    spuSaleAttrList.some(item => item.spuSaleAttrValueList.length == 0)
  )
    return ElMessage.error("属性值不能为空，请添加。。。")

  const id = baseSaleAttrList.value.find(
    item => item.name == spuInfo.spuSaleAttr
  ).id

  spuInfo.spuSaleAttrList.push({
    baseSaleAttrId: id, //添加一个id标识 ，
    inputVisible: false, // 给当前行对象添加一个属性，用于控制按钮和输入框的显示
    saleAttrName: spuInfo.spuSaleAttr, // 属性名 颜色 版本  尺寸
    spuSaleAttrValueList: [], // 当前属性名对应的那些详细的属性值
  })

  // 清空select框
  spuInfo.spuSaleAttr = ""
  // 清空下拉框校验规则
  spuFormRef.value!.clearValidate(["spuSaleAttrList"])
}

// 7. 使用计算属性 来处理销售属性的显示
const filterBaseSaleAttrList = computed(() => {
  return baseSaleAttrList.value.filter(item => {
    return !spuInfo.spuSaleAttrList.find(
      attr => attr.saleAttrName === item.name
    )
  })
})

// 8. 删除销售属性
const deleteAttr = (index: number) => {
  spuInfo.spuSaleAttrList.splice(index, 1)
}

// 9.属性值列表 tag 的三个函数
// 删
const handleClose = (row, tag) => {
  row.spuSaleAttrValueList.splice(row.spuSaleAttrValueList.indexOf(tag), 1)
}
// 显示input框
const showInput = row => {
  row.inputVisible = true
  nextTick(() => {
    InputRef.value!.input!.focus()
  })
}
// 增加/修改
const handleInputConfirm = row => {
  if (inputValue.value.trim()) {
    const spuSaleAttrValueList = row.spuSaleAttrValueList
    if (
      spuSaleAttrValueList.length &&
      spuSaleAttrValueList.some(
        item => item.saleAttrValueName === inputValue.value
      )
    ) {
      row.inputVisible = false
      inputValue.value = ""
      return ElMessage.error("属性值已存在，重新输入")
    }

    const id = baseSaleAttrList.value.find(
      item => item.name === row.saleAttrName
    ).id

    row.spuSaleAttrValueList.push({
      baseSaleAttrId: id,
      saleAttrName: row.saleAttrName,
      saleAttrValueName: inputValue.value,
    })
  }
  row.inputVisible = false
  inputValue.value = ""
}

// 10.保存spu属性 表单校验 上传属性
const spuSubmitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      // 再判断一下，基础销售是不是有属性值，如果有一项无值 不能提交
      const spuSaleAttrList = spuInfo.spuSaleAttrList
      if (
        spuSaleAttrList.length &&
        spuSaleAttrList.every(item => !item.spuSaleAttrValueList.length)
      )
        return ElMessage.error("有属性值为空，请添加...")

      // 对最终上传的图片进行处理
      spuInfo.spuImageList = spuInfo.spuImageList.map(item => {
        return {
          imgName: item.name,
          imgUrl: item.response?.data || item.erl,
        }
      })

      spuInfo.category3Id = categoryStore.category3Id

      if (spuInfo.id) {
        // 调用更新函数
        await reqUpdateSpuInfo(spuInfo)
      } else {
        // 调用添加函数
        await reqSaveSpuInfo(spuInfo)
      }

      ElMessage.success("操作Spu成功")
      // 跳转到列表页
      emits("changeScene", 1)
    } else {
      ElMessage.error("提交失败...")
    }
  })
}
</script>

<style></style>
